using System;
using Cinemachine;
using DG.Tweening;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Super
{
	public class VirtualCM2DManager : BaseSingle<VirtualCM2DManager>
	{
		public bool enableDragMove = false;
		public bool enableFollow = false;
		public bool enableScale = false;

		public MouseKey mouseDragKey;
		public CinemachineVirtualCamera virtualCM;
		public CinemachineConfiner2D confiner2D;
		public Transform moveTf;

		public float moveFactor;
		public float scaleFactor;
		public Vector2 scaleRange = new Vector2(5, 10);

		public override void OnInit()
		{
			base.OnInit();

			EventManager.Register<MouseDragGE>(OnMouseDragGE);
			EventManager.Register<MouseScrollGE>(OnMouseScroll, 1);
		}

		#region 外部函数
		// 设置拖拽移动
		public static void SetDragMoveKey(bool canDrag, MouseKey key)
		{
			Ins.enableDragMove = canDrag;
			Ins.mouseDragKey = key;
			
			
			Ins.virtualCM.Follow = Ins.moveTf;
		}

		// 设置跟随目标
		public static void SetFollowTarget(Transform target)
		{
			Ins.enableFollow = true;
			Ins.virtualCM.Follow = target;

			Ins.enableDragMove = false;
		}
		
		// 设置移动范围
		public void SetConfiner2D(GameObject gameObject)
		{
			if (gameObject == null)
			{
				if (confiner2D != null) Destroy(confiner2D);
				return;
			}
			confiner2D = virtualCM.GetComponent<CinemachineConfiner2D>();
			if (confiner2D == null)
				confiner2D = virtualCM.gameObject.AddComponent<CinemachineConfiner2D>();
				
			confiner2D.m_BoundingShape2D = gameObject.GetComponent<PolygonCollider2D>();
			confiner2D.InvalidateCache();
		}

		public static void Scale(bool state, Vector2 scaleRange)
		{
			Ins.enableScale = state;
			Ins.scaleRange = scaleRange;
		}

		public static void CancelFollow()
		{
			Ins.enableFollow = false;
			Ins.virtualCM.Follow = null;
		}
		
		// 设置镜头中心
		public void SetFocus(Vector2 pos)
		{
			Rect moveRect = GetMoveableArea();
			pos = new Vector2(Mathf.Clamp(pos.x, moveRect.xMin, moveRect.xMax), Mathf.Clamp(pos.y, moveRect.yMin, moveRect.yMax));
			moveTf.position = pos;
		}
		
		public void SetSlowFocus(Vector2 pos, float time)
		{
			Vector2 oriPos = moveTf.position;
			DOTween.To((curTime)=>
			{
				Vector2 curPos = oriPos + (pos - oriPos) * curTime;
				SetFocus(curPos);
			}, 0, 1, time).OnKill(()=>SetFocus(pos));
		}
		
		#endregion
		
		#region 回调函数

		private void OnMouseDragGE(MouseDragGE gE)
		{
			if (EventSystem.current.IsPointerOverGameObject()) return;	// 鼠标在ui上，不响应
			if (!enableDragMove || mouseDragKey != gE.key) return;
			
			float factor = virtualCM.m_Lens.OrthographicSize * 2 * moveFactor / ValueSettingSO.Ins.bestScreenHeight;
			Vector2 offset = InputManager.Ins.mouseInfo.offsetPos * factor;

			Vector2 pos = moveTf.position - (Vector3)offset;
			SetFocus(pos);
		}
		
		private void OnMouseScroll(MouseScrollGE gE)
		{
			if (!enableScale) return;
			float value = virtualCM.m_Lens.OrthographicSize - gE.delta.y * scaleFactor;
			value = Mathf.Clamp(value, scaleRange.x, scaleRange.y);
			virtualCM.m_Lens.OrthographicSize = value;
			confiner2D?.InvalidateCache();
		}
		
		#endregion
		
		#region 私有函数
		
		private static void Reset()
		{
			SetDragMoveKey(false, MouseKey.Left);
			CancelFollow();
			Scale(false, Vector2.zero);
		}
		
		private Rect GetMoveableArea()
		{
			if (confiner2D == null || confiner2D.m_BoundingShape2D == null) return new Rect(-30, -20, 60, 40);
			PolygonCollider2D polygonCollider2D = confiner2D.m_BoundingShape2D.GetComponent<PolygonCollider2D>();
			float len = virtualCM.m_Lens.OrthographicSize;
			Transform colliderTf = polygonCollider2D.GetComponent<Transform>();
			float wid = MathF.Abs(polygonCollider2D.points[0].x) * colliderTf.localScale.x * 2 - len * virtualCM.m_Lens.Aspect * 2;
			float hei = MathF.Abs(polygonCollider2D.points[0].y) * colliderTf.localScale.y * 2 - len * 2;
			
			Rect rect = new Rect(-wid * 0.5f, -hei * 0.5f, wid, hei);
			return rect;
		}
		
		#endregion
	}


}
